package com.hemerasolutions.v2trainer.model.training;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;

import com.hemerasolutions.v2trainer.model.base.BaseModel;
import com.hemerasolutions.v2trainer.model.exercise.Exercise;
import com.hemerasolutions.v2trainer.model.exerciseGroup.ExerciseGroup;
import com.hemerasolutions.v2trainer.model.interfaces.BaseReferencedModelInterface;
import com.hemerasolutions.v2trainer.model.modality.Modality;
import com.hemerasolutions.v2trainer.model.users.User;
import com.hemerasolutions.v2trainer.util.Utility;
import com.hemerasolutions.v2trainer.util.annotations.ReferencedModel;

@Entity
public class Training extends BaseModel implements BaseReferencedModelInterface {
 
	private static final long serialVersionUID = 1L;

    @Column
	private boolean trainingSystem;
	
    @Column(length = 50)
	private String name;
	 
    @Column(length = 180)    
	private String description;
	 
    @Column(length = 180)    
	private String obs;

    @Column(length = 3)
    private int version;
    
    @Temporal(javax.persistence.TemporalType.TIMESTAMP)	
	private Date createdAt;

    @Temporal(javax.persistence.TemporalType.TIMESTAMP)
	private Date lastChange;

	@OneToOne 
    private User changedBy;
	
	private static String nameKey1 = "Training";

	private static String nameKey2 = "TrainingSystem";

    public static final int TRAINING_SYSTEM = 1;
    		
 	public static final int TRAINING = 2;
 	
 	public static final int DAILYTRAINING = 3;
    			
	
	@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY,mappedBy="training",orphanRemoval=true)
    private List<TrainingStep> trainingSteps;

    
    @ManyToMany
    @ReferencedModel(compareOnChange=false)
    private List<Modality> usedModalitys;
    
    @ManyToMany
    @ReferencedModel(compareOnChange=false)
    private List<Exercise> usedExercises;
    

    @ManyToMany(mappedBy="usedTrainings",fetch=FetchType.LAZY)
    @ReferencedModel(compareOnChange=false)
    private List<ExerciseGroup> usedExerciseGroups;
    
    @ManyToMany(fetch=FetchType.LAZY)
    @ReferencedModel(compareOnChange=false)
    private List<Training> usedTrainings;
    
    @ManyToOne
    private VersionableTraining versionableTraining;

 	
 	public Training(Training other, VersionableTraining versionableTraining){
 		this();

 		this.trainingSystem = other.trainingSystem;
 		this.name = other.name;
 		this.description = other.description;
 		this.obs = other.obs;

 		this.lastChange = Utility.getRoundedDate();
 		this.createdAt = Utility.getRoundedDate();
 		this.changedBy = other.changedBy;
 		this.versionableTraining = versionableTraining;

 		for(TrainingStep ts: other.trainingSteps){
 			this.trainingSteps.add(new TrainingStep(ts,this));
 		}
 		
 	}
    
    
	public Training() {
		super();
		this.id = null;
		this.trainingSteps = new ArrayList<TrainingStep>();
	}

	public void prepareLevels() {
		boolean found;
		for(int i = 0; i < 6; i++){
			found = false;
			for(TrainingStep tStep :this.trainingSteps){
				if(tStep.getLevel() == i){
					found = true; 
					break;
				}
			}
			if(!found){
				TrainingStep tStep = new TrainingStep();
				tStep.setLevel(i);
				tStep.setTraining(this);
				trainingSteps.add(i,tStep);
			}
		}
	}		
	
	
	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	public Integer getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public String getDescription() {
		return description;
	}

	public String getObs() {
		return obs;
	}


	public Date getCreatedAt() {
		return createdAt;
	}

	public Date getLastChange() {
		return lastChange;
	}

	public User getChangedBy() {
		return changedBy;
	}

	public List<TrainingStep> getTrainingSteps() {
		return trainingSteps;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public void setObs(String obs) {
		this.obs = obs;
	}

	public void setCreatedAt(Date createdAt) {
		this.createdAt = createdAt;
	}

	public void setLastChange(Date lastChange) {
		this.lastChange = lastChange;
	}

	public void setChangedBy(User changedBy) {
		this.changedBy = changedBy;
	}

	public void setTrainingSteps(List<TrainingStep> trainingSteps) {
		this.trainingSteps = trainingSteps;
	}

	public int getVersion() {
		return version;
	}

	public void setVersion(int version) {
		this.version = version;
	}

	public boolean isTrainingSystem() {
		return trainingSystem;
	}

	public void setTrainingSystem(boolean trainingSystem) {
		this.trainingSystem = trainingSystem;
	}

	public VersionableTraining getVersionableTraining() {
		return versionableTraining;
	}

	public void setVersionableTraining(VersionableTraining versionableTraining) {
		this.versionableTraining = versionableTraining;
	}
	
	public List<Modality> getUsedModalitys() {
		return usedModalitys;
	}

	public void setUsedModalitys(List<Modality> usedModalitys) {
		this.usedModalitys = usedModalitys;
	}


	public List<Exercise> getUsedExercises() {
		return usedExercises;
	}


	public void setUsedExercises(List<Exercise> usedExercises) {
		this.usedExercises = usedExercises;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((changedBy == null) ? 0 : changedBy.hashCode());
		result = prime * result
				+ ((createdAt == null) ? 0 : createdAt.hashCode());
		result = prime * result
				+ ((description == null) ? 0 : description.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result
				+ ((lastChange == null) ? 0 : lastChange.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result + ((obs == null) ? 0 : obs.hashCode());
		result = prime * result + (trainingSystem ? 1231 : 1237);
		result = prime * result + version;
		result = prime
				* result
				+ ((versionableTraining == null) ? 0 : versionableTraining
						.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		Training other = (Training) obj;
		if (changedBy == null) {
			if (other.changedBy != null) {
				return false;
			}
		} else if (!changedBy.equals(other.changedBy)) {
			return false;
		}
		if (createdAt == null) {
			if (other.createdAt != null) {
				return false;
			}
		} else if (!createdAt.equals(other.createdAt)) {
			return false;
		}
		if (description == null) {
			if (other.description != null) {
				return false;
			}
		} else if (!description.equals(other.description)) {
			return false;
		}
		if (id == null) {
			if (other.id != null) {
				return false;
			}
		} else if (!id.equals(other.id)) {
			return false;
		}
		if (lastChange == null) {
			if (other.lastChange != null) {
				return false;
			}
		} else if (!lastChange.equals(other.lastChange)) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		if (obs == null) {
			if (other.obs != null) {
				return false;
			}
		} else if (!obs.equals(other.obs)) {
			return false;
		}
		if (trainingSystem != other.trainingSystem) {
			return false;
		}
		if (version != other.version) {
			return false;
		}
		if (versionableTraining == null) {
			if (other.versionableTraining != null) {
				return false;
			}
		} else if (!versionableTraining.equals(other.versionableTraining)) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		return "Training [id=" + id + ", trainingSystem=" + trainingSystem
				+ ", name=" + name + ", description=" + description + ", obs="
				+ obs + ", version=" + version + ", createdAt=" + createdAt
				+ ", lastChange=" + lastChange + ", changedBy=" + changedBy
				+ ", versionableTraining=" + versionableTraining + "]";
	}


	@Override
	public String getNameKey() {

		if(this.trainingSystem){
			return nameKey1;
		}else{
			return nameKey2;
		}
	}


	@Override
	public void fillReferences() {	
		this.usedModalitys = new ArrayList<Modality>();
		this.usedTrainings = new ArrayList<Training>();
		this.usedExerciseGroups = new ArrayList<ExerciseGroup>();
		this.usedExercises = new ArrayList<Exercise>();
		
		for(TrainingStep ts:this.trainingSteps){
			for(Modality mod:ts.collectModalitys()){
				if(!this.usedModalitys.contains(mod)){
					this.usedModalitys.add(mod);
				}
			}
			for(Training subTraining:ts.collectTainings()){
				if(!this.usedTrainings.contains(subTraining)){
					this.usedTrainings.add(subTraining);
				}
			}
			for(ExerciseGroup eg:ts.collectExerciseGroups()){
				if(!this.usedExerciseGroups.contains(eg)){
					this.usedExerciseGroups.add(eg);
				}
			}

			for(Exercise ex:ts.collectExercises()){
				if(!this.usedExercises.contains(ex)){
					this.usedExercises.add(ex);
				}
			}
		}
	}
	
}

 
